package com.androwit.engine;

import com.androwit.engine.mapping.MappingField;
import com.androwit.engine.mapping.MappingFieldsDefiner;

/**
 * This interface handles the io bridge
 * 
 * @param <K>
 *          the key type
 * @param <V>
 *          the target value type
 * @param <I>
 *          the item type
 * @param <O>
 *          the output type
 * 
 * 
 * @author Zied Hamdi Founder of http://1vu.fr, Zied Hamdi
 * 
 */
public interface MappingPersister<K, V, I, O> {

	/**
	 * 
	 * writes a Record into <code>output</code> returns an updated version of
	 * output
	 * 
	 * @param field
	 *          key
	 * @param value
	 *          value
	 * @param output
	 *          output
	 * @return returns an updated version of output
	 */
	O writeField(MappingField<?, K, V> field, V value, O output);

	/**
	 * 
	 * creates an Output object for an Item
	 * 
	 * @param input
	 *          the input item the output is created for
	 * @return a ready to write in item (via
	 *         {@link #writeField(Object, Object, Object)})
	 */
	O createOutputItem(I input, MappingFieldsDefiner<?, K, V> definer);

	/**
	 * 
	 * called on each item treatment end. You may flush on each item or have a
	 * more complex flushing strategy
	 * 
	 * @param output
	 *          output
	 * 
	 * @return what is meaningful for your persistence (typically flush the line)
	 */
	Object flush(O output);

	/**
	 * 
	 * closes the writer. You must expect to receive null either if there was no
	 * data to process or if you implementation of
	 * {@link #createOutputItem(Object)} returns null
	 * 
	 * @param output
	 *          the last used output (if you have a flushing strategy, you may
	 *          want to flush the remaining data a this point)
	 * 
	 * @return any meaningful object for your environment
	 */
	Object close(O output);

	/**
	 * returns the key of the object: this method is not used by the library, it
	 * is here to remind you that you must have a method to extract the id from
	 * your objects
	 * 
	 * @param input
	 *          instance
	 * @return the key
	 */
	Object getKey(I input, MappingFieldsDefiner<?, K, V> definer);

	/**
	 * Called before the start of processing a list of entries
	 */
	void open();

	/**
	 * Called if an exception occurs.
	 * 
	 * @param ex
	 *          the exception that occured
	 * @return the exception that should be thrown
	 */
	Exception handleException(Exception ex);

}
